

(function() {
    const inBrowser = typeof window !== 'undefined'
    const supportTouch = inBrowser && 'ontouchstart' in window
    let initiated = false
    let eventTarget
    
    const isMousedown = (eventType) => eventType === 'mousedown'
    
    const isMousemove = (eventType) => eventType === 'mousemove'
    
    const isMouseup = (eventType) => eventType === 'mouseup'
    
    const isUpdateTarget = (eventType) =>
      isMousedown(eventType) || !eventTarget || (eventTarget && !eventTarget.dispatchEvent)
    
    function Touch(target, identifier, mouseEvent) {
      const { clientX, clientY, screenX, screenY, pageX, pageY } = mouseEvent
    
      this.identifier = identifier
      this.target = target
      this.clientX = clientX
      this.clientY = clientY
      this.screenX = screenX
      this.screenY = screenY
      this.pageX = pageX
      this.pageY = pageY
    }
    
    function createTouchList() {
      const touchList = []
    
      touchList.item = function (index) {
        return this[index] || null
      }
    
      touchList.identifiedTouch = function (id) {
        return this[id + 1] || null
      }
    
      return touchList
    }
    
    function createTouchListWithEvent(mouseEvent) {
      const touchList = createTouchList()
      touchList.push(new Touch(eventTarget, 1, mouseEvent))
      return touchList
    }
    
    function getActiveTouches(mouseEvent) {
      const { type } = mouseEvent
    
      if (isMouseup(type)) {
        return createTouchList()
      }
    
      return createTouchListWithEvent(mouseEvent)
    }
    
    function triggerTouch(touchType, mouseEvent) {
      const { altKey, ctrlKey, metaKey, shiftKey } = mouseEvent
      const touchEvent = new Event(touchType, { bubbles: true, cancelable: true })
    
      touchEvent.altKey = altKey
      touchEvent.ctrlKey = ctrlKey
      touchEvent.metaKey = metaKey
      touchEvent.shiftKey = shiftKey
    
      touchEvent.touches = getActiveTouches(mouseEvent)
      touchEvent.targetTouches = getActiveTouches(mouseEvent)
      touchEvent.changedTouches = createTouchListWithEvent(mouseEvent)
    
      eventTarget.dispatchEvent(touchEvent)
    }
    
    function onMouse(mouseEvent, touchType) {
      const { type, target } = mouseEvent
    
      initiated = isMousedown(type) ? true : isMouseup(type) ? false : initiated
    
      if (isMousemove(type) && !initiated) return
    
      if (isUpdateTarget(type)) eventTarget = target
    
      triggerTouch(touchType, mouseEvent)
    
      if (isMouseup(type)) eventTarget = null
    }
    
    function createTouchEmulator() {
      window.addEventListener('mousedown', (event) => onMouse(event, 'touchstart'), true)
      window.addEventListener('mousemove', (event) => onMouse(event, 'touchmove'), true)
      window.addEventListener('mouseup', (event) => onMouse(event, 'touchend'), true)
    }
    
    if (inBrowser && !supportTouch) {
      createTouchEmulator()
    }
    
        
})();



